// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.
//
// ███╗   ██╗ ██████╗ ████████╗██╗ ██████╗███████╗
// ████╗  ██║██╔═══██╗╚══██╔══╝██║██╔════╝██╔════╝
// ██╔██╗ ██║██║   ██║   ██║   ██║██║     █████╗
// ██║╚██╗██║██║   ██║   ██║   ██║██║     ██╔══╝
// ██║ ╚████║╚██████╔╝   ██║   ██║╚██████╗███████╗
// ╚═╝  ╚═══╝ ╚═════╝    ╚═╝   ╚═╝ ╚═════╝╚══════╝
// ------------------------------------------------
//
// This file is automatically generated.
// Please do not edit these files manually.
//
// ------------------------------------------------

#nullable restore

using Elastic.Clients.Elasticsearch.Core;
using Elastic.Clients.Elasticsearch.Fluent;
using Elastic.Clients.Elasticsearch.Serialization;
using Elastic.Transport;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Elastic.Clients.Elasticsearch.Core.Search;

public partial interface ISuggest
{
}

[GenericConverter(typeof(SuggestDictionaryConverter<>), unwrap: true)]
public partial class SuggestDictionary<TDocument> : IsAReadOnlyDictionary<string, IReadOnlyCollection<ISuggest>>
{
	public SuggestDictionary(IReadOnlyDictionary<string, IReadOnlyCollection<ISuggest>> backingDictionary) : base(backingDictionary)
	{
	}

	public IReadOnlyCollection<Elastic.Clients.Elasticsearch.Core.Search.CompletionSuggest<TDocument>>? GetCompletion(string key) => TryGet<Elastic.Clients.Elasticsearch.Core.Search.CompletionSuggest<TDocument>>(key);
	public IReadOnlyCollection<Elastic.Clients.Elasticsearch.Core.Search.PhraseSuggest>? GetPhrase(string key) => TryGet<Elastic.Clients.Elasticsearch.Core.Search.PhraseSuggest>(key);
	public IReadOnlyCollection<Elastic.Clients.Elasticsearch.Core.Search.TermSuggest>? GetTerm(string key) => TryGet<Elastic.Clients.Elasticsearch.Core.Search.TermSuggest>(key);
	private IReadOnlyCollection<T>? TryGet<T>(string key) where T : class, ISuggest => BackingDictionary.TryGetValue(key, out var value) ? value.Cast<T>().ToArray() : null;
}

internal sealed partial class SuggestDictionaryConverter<TDocument> : JsonConverter<SuggestDictionary<TDocument>>
{
	public override SuggestDictionary<TDocument> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
	{
		var dictionary = new Dictionary<string, IReadOnlyCollection<ISuggest>>();
		if (reader.TokenType != JsonTokenType.StartObject)
			throw new JsonException($"Expected {JsonTokenType.StartObject} but read {reader.TokenType}.");
		while (reader.Read() && reader.TokenType != JsonTokenType.EndObject)
		{
			if (reader.TokenType != JsonTokenType.PropertyName)
				throw new JsonException($"Expected {JsonTokenType.PropertyName} but read {reader.TokenType}.");
			var name = reader.GetString();
			reader.Read();
			ReadItem(ref reader, options, dictionary, name);
		}

		return new SuggestDictionary<TDocument>(dictionary);
	}

	public override void Write(Utf8JsonWriter writer, SuggestDictionary<TDocument> value, JsonSerializerOptions options)
	{
		throw new NotImplementedException("'SuggestDictionary' is a readonly type, used only on responses and does not support being written to JSON.");
	}

	public static void ReadItem(ref Utf8JsonReader reader, JsonSerializerOptions options, Dictionary<string, IReadOnlyCollection<ISuggest>> dictionary, string name)
	{
		var nameParts = name.Split('#');
		if (nameParts.Length != 2)
			throw new JsonException($"Unable to parse typed-key '{name}'.");
		var type = nameParts[0];
		switch (type)
		{
			case "completion":
				{
					var item = JsonSerializer.Deserialize<IReadOnlyCollection<Elastic.Clients.Elasticsearch.Core.Search.CompletionSuggest<TDocument>>>(ref reader, options);
					dictionary.Add(nameParts[1], item);
					break;
				}

			case "phrase":
				{
					var item = JsonSerializer.Deserialize<IReadOnlyCollection<Elastic.Clients.Elasticsearch.Core.Search.PhraseSuggest>>(ref reader, options);
					dictionary.Add(nameParts[1], item);
					break;
				}

			case "term":
				{
					var item = JsonSerializer.Deserialize<IReadOnlyCollection<Elastic.Clients.Elasticsearch.Core.Search.TermSuggest>>(ref reader, options);
					dictionary.Add(nameParts[1], item);
					break;
				}

			default:
				throw new NotSupportedException($"The tagged variant '{type}' is currently not supported.");
		}
	}
}